FindFromUnion<R, Key, Value>
recordのunionから1つを抽出する
以下は同じになる
code:ts
type A = FindFromUnion<TrafficLight, 'light', 'red'>;
type B = Extract<TrafficLight, { light: 'red' }>;
定義
code:ts
type FindFromUnion<
R extends Record<string, unknown>,
Key extends keyof R,
= Extract<R, Record<Key, Value>>;
利用例
code:ts
type TrafficLight =
| { light: "red"; action: "stop" }
| { light: "yellow"; action: "slow down" }
| { light: "green"; action: "go" };
type A = FindFromUnion<TrafficLight, "light", "red">; // { light: "red"; action: "stop" }
union型TrafficLightから、light === 'red'なものを抽出している
switch文に型をつける例
code:ts
export const actionFromLight = <Light extends TrafficLight"light">( light: Light
): FindFromUnion<TrafficLight, "light", Light>"action" => { switch (light) {
case "red":
return "stop" as any;
case "yellow":
return "slow down" as any;
case "green":
return "go" as any;
default:
return exhaustiveCheck(light);
}
};
↑型推論の問題でas anyを付けないとエラーになる
これ、TrafficLightの内容が変わった時にエラーにならないので渋い...mrsekut.icon
こうすれば、引数から返り値が決定する
code:ts
const action = actionFromLight("red"); // 'stop'
定義の意味
例えば、簡易化した以下のような型を見る
code:ts
type Red = Extract<TrafficLight, { light: "red" }>;
// ↑{ light: "red"; action: "stop" }
これは以下を全て抑えていないと理解できない
code:ts
type Extract<U, G> = U extends G ? U : never;
UがGの部分型ならUを返す
今回はUがUnion型なので、dirstributeして評価される
{ light: "red"; action: "stop" } <: { light: "red"}だということ
従って、
{ light: "red"; action: "stop" } extends { light: "red"}が真となり、
部分型の方である{ light: "red"; action: "stop" }が返る